// locutor
// (c) 2009, Normen Müller, normen.mueller@gmail.com  
// $Id: Rippler.scala 4 2009-11-06 19:59:06Z normen.mueller $
package locutor.cia

import scaup.Views._
import scaup.io.{Process => execute}

import scalaxx.diff.{Command, append, remove, update, before}

import locutor.model.{GraphModel, RuleSystem, DependencyGraph}

/** Companion to <code>Rippler</code> class.
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
private [locutor] object Rippler {
  
  def ripple(δ: List[Command]) = new Rippler(δ)    

}

/** A class for rippling effects into a dependency graph.
 * 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.1 */
private [locutor] class Rippler(delta: List[Command]) {
  
  private val Tmp     = System.getProperty("locutor.tmp", System.getProperty("java.io.tmpdir")).toFile
  private val GrGen   = System.getProperty("locutor.grgen") + "/GrGen "
  private val GrShell = System.getProperty("locutor.grgen") + "/GrShell -N "
  
  def withKnowledgeBase(graph: DependencyGraph, rules: RuleSystem) = {
    val grgen = execute(GrGen + flushRewriteSystem(graph, rules).filename, Tmp)
    grgen.waitFor match {
      case 0 => Map() ++ (delta map (c => (c, computeAffected(graph, c))))        
      case _ => error("Fatal rippling error during graph rewrite system generation.")
    }
  }
  
  private def computeAffected(graph: DependencyGraph, command: Command) = {
    val shell = execute(GrShell + flushDependencyGraph(graph, rewriteSeqOf(graph, command)).filename, Tmp)
    shell.waitFor match {
      case 0 => ImpactGraph.parse(Tmp / "affected.grs")        
      case _ => error("Fatal rippling error during computation of implicit affected items.")
    }
  }
  
  private def rewriteSeqOf(graph: DependencyGraph, command: Command) = command match {
    case append(xpath, instruction@_*) => ""
    case before(xpath, instruction@_*) => ""
    case remove(xpath, instruction@_*) =>
      graph \ xpath match {
        case Some(infom) => "xgrs <markRemoved("+infom.id+") & rippleRemoved* & slurp*>"
        case None        => error("Fatal rippling error during identification of local affected item.")
      }
    case update(xpath, instruction@_*) => ""
  }
  
  private def flushRewriteSystem(graph: DependencyGraph, rules: RuleSystem) = {
    (graph.model.statements mkString ("", "\n", "\n")) >>> (Tmp / (graph.model.name + ".gm"))
    (("using " + graph.model.name + ";\n") + (rules.statements mkString ("", "\n", "\n"))) >>> (Tmp / (rules.name + ".grg"))
  }
  
  private def flushDependencyGraph(graph: DependencyGraph, xgrs: String) = {
    val buf = new StringBuilder
    buf append "new graph \"lgsp-"+graph.model.name+"Model.dll\"\n"
    buf append "select actions \"lgsp-"+graph.model.name+"Actions.dll\"\n"
    for(node <- graph.V) buf append "new " append node append "\n"
    for(edge <- graph.E) buf append "new " append edge append "\n"
    buf append "validate strict\n"
    buf append xgrs append "\n"
    buf append "export affected.grs\n"
    buf append "exit\n"    
    buf.toString >>> (Tmp / (graph.model.name+".grs"))
  }  
  
}
